package com.java.interview.thread;

import org.junit.Test;

import java.util.Random;

/**
 * Created by lyc on 2016-03-25.
 */
//让多线程代码安全运行的方法就是让所以的方法都通步，然而这样会带来的问题就是线程之间可能发生死锁。
public class InterviewDelLock {
    //借助一个学术论文中使用的经典模型来诠释死锁--哲学家进餐问题
    //五位哲学家围绕一个圆桌，桌上有5支筷子；哲学家的状态可能是“思考”或者“饥饿”。
    //如果饥饿将拿起两变的筷子并进餐一段时间，进餐结束后，哲学家会放回筷子。
    class Philosopher extends  Thread{
        private Chopstick left,right;
        private Random random;

        public Philosopher(Chopstick left,Chopstick right){
              this.left=left;
            this.right=right;
            random=new Random();
        }

        public  void run(){

            while (true){
                try {
                    Thread.sleep(random.nextInt(1000));//思考一段时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (left){                  //拿起筷子1
                    synchronized (right){             //拿起筷子2
                        try {
                            Thread.sleep(random.nextInt(1000));//进餐一段时间
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
    class Chopstick{}
    //稍加分析：如果哲学家同事决定进餐，都拿起左边的筷子，那么就没办法进行下去；
    //所有人都持一只筷子并等待右手边的人放下筷子，那么这个时候就死锁了。
    //解决死锁：按照全局的固定顺序来获取多把锁
    //我们不在按照左边和右边的顺序拿起筷子，而是按照筷子的编号来锁。


//    总结：线程与锁模型带来的三个主要危害-竞太条件、死锁和内存可见性
//        避免危害的准则：
//        对共享变量的所有访问都需要通步化；
//        读线程和写线程都需要同步化；
//        按照约定的全局顺序来获取多把锁；
//        当持有锁时避免调用外星方法；
//        持有锁的时间应尽量可能短

}
